package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @author atguigu-mqx
 */
@Component
public class AuthGlobalFilter implements GlobalFilter {

    @Autowired
    private RedisTemplate redisTemplate;

    @Value("${authUrls.url}")
    private String authUrls;    //  authUrls=trade.html,myOrder.html,list.html
    //  创建一个对象
    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //  获取用户的请求
        ServerHttpRequest request = exchange.getRequest();
        //  获取用户请求的URL
        //  http://localhost/api/product/inner/getSkuInfo/24
        //  path = api/product/inner/getSkuInfo/24
        //  request.getURI() = http://localhost/api/product/inner/getSkuInfo/24
        String path = request.getURI().getPath();

        //  判断用户是否访问内部数据接口
        if (antPathMatcher.match("/**/inner/**",path)){
            //  说明用户在访问内部数据接口，提示！
            ServerHttpResponse response = exchange.getResponse();
            //  停止运行
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //  判断用户是否访问带有/auth/这样的路径数据！ 如果带有，只有用户登录情况下才能访问！
        //  获取到用户Id
        String userId = this.getUserId(request);
        //  获取临时用户Id
        String userTempId = this.getUserTempId(request);

        //  判断
        if("-1".equals(userId)){
            //  获取响应对象
            ServerHttpResponse response = exchange.getResponse();
            //  停止运行
            return out(response, ResultCodeEnum.PERMISSION);
        }

        //  判断
        if (antPathMatcher.match("/api/**/auth/**",path)){
            //  判断用户Id
            if (StringUtils.isEmpty(userId)){
                //  获取响应对象
                ServerHttpResponse response = exchange.getResponse();
                //  停止运行
                return out(response, ResultCodeEnum.LOGIN_AUTH);
            }
        }

        //  判断用户访问的是哪种控制器！如果访问黑名单中的控制器，则停止用户访问！并提示用户登录！
        //  path = http://list.gmall.com/list.html?category3Id = 61;
        //  authUrls.url: trade.html,myOrder.html,list.html
        String[] split = authUrls.split(",");
        if (split!=null && split.length >0 ){
            for (String url : split) { //   0 url trade.html 1 url myOrder.html 2 url list.html
                //  包含上述url 并且 用户Id 为空！ 此时需要提示用户登录！
                if (path.indexOf(url)!=-1 && StringUtils.isEmpty(userId)){
                    //  获取到响应对象
                    ServerHttpResponse response = exchange.getResponse();
                    //  设置重定向相关参数：
                    response.setStatusCode(HttpStatus.SEE_OTHER);
                    //  重定向的URL地址！
                    //  response.getHeaders().set(HttpHeaders.LOCATION,"http://www.gmall.com/login.html?originUrl="+request.getURI());
                    response.getHeaders().set(HttpHeaders.LOCATION,"http://passport.gmall.com/login.html?originUrl="+request.getURI());
                    //  设置一下重定向
                    return response.setComplete();
                }
            }
        }

        //  需要将用户Id,将用户Id 设置到请求头中，传递给后台微服务！
        if (!StringUtils.isEmpty(userId) || !StringUtils.isEmpty(userTempId)){
            //  如何设置请求头！
            //  响应对象： ServerHttpResponse response = exchange.getResponse()
            //  请求对象： ServerHttpRequest request1 = exchange.getRequest();
            //  chain: 过滤器链对象
            //  exchange： web 对象！
            // 类似于： header("key",value);

            //  ServerHttpRequest request
            //  设置临时用户Id
            if (!StringUtils.isEmpty(userTempId)){
                request.mutate().header("userTempId", userTempId).build();
            }
            //  设置登录userId
            if (!StringUtils.isEmpty(userId)){
                 request.mutate().header("userId", userId).build();
            }
            //  设置完成之后，要返回对应的数据！
            //  request ---> exchange 对象！
              return chain.filter(exchange.mutate().request(request).build());
        }
        //  默认返回！
        return chain.filter(exchange);
    }


    private String getUserTempId(ServerHttpRequest request) {
        //  临时用户Id 存储到cookie 了,同时也存储到了请求中！
        String userTempId = "";
        List<String> stringList = request.getHeaders().get("userTempId");
        if (!CollectionUtils.isEmpty(stringList)){
            userTempId = stringList.get(0);
        }else {
            //  从cookie 中获取！
            HttpCookie httpcookie = request.getCookies().getFirst("userTempId");
            if (httpcookie!=null){
                userTempId = httpcookie.getValue();
            }
        }
        //  返回数据
        return userTempId;
    }

    /**
     * 用户提示方法
     * @param response
     * @param resultCodeEnum
     * @return
     */
    private Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum) {
        //  输入的内容是：message信息
        Result<Object> result = Result.build(null, resultCodeEnum);
        //  将result 转换为字符串 或 字节数组！
        String printStr = JSON.toJSONString(result);
        //  设置字符集编码
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        //  要输出result 对象数据！
        DataBuffer wrap = response.bufferFactory().wrap(printStr.getBytes());
        //  输出数据！
        return response.writeWith(Mono.just(wrap));
    }

    /**
     * 获取用户Id
     * @param request
     * @return
     */
    private String getUserId(ServerHttpRequest request) {
        //  userId 存储在缓存中！
        //  考虑： token 如何获取?  cookie  ,header !
        String token = "";
        List<String> stringList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(stringList)){
            token = stringList.get(0);
        }else {
            //  从cookie 中获取！
            HttpCookie httpcookie = request.getCookies().getFirst("token");
            if (httpcookie!=null){
                token = httpcookie.getValue();
            }
        }
        //  判断token不为空！
        if (!StringUtils.isEmpty(token)){
            //  登录key
            String loginKey = "user:login:"+ token;

            //  获取缓存中数据
            String strJson = (String) this.redisTemplate.opsForValue().get(loginKey);
            JSONObject jsonObject = JSONObject.parseObject(strJson);
            //  存储ip userId
            if (jsonObject!=null){
                //  获取缓存中的Ip 地址
                String ip = (String) jsonObject.get("ip");
                if (ip.equals(IpUtil.getGatwayIpAddress(request))){
                    String userId = (String) jsonObject.get("userId");
                    return userId;
                }else {
                    return "-1";
                }
            }
        }

        //  没有则返回空！
        return "";
    }


}
